Ext.ComponentQuery = new function() {
    var cq = this,

        
        // 选择器中表达式的字符串模版
        filterFnPattern = [
            'var r = [],',
                'i = 0,',
                'it = arguments[0],',
                'l = it.length,',
                'c;',
            'for (; i < l; i++) {',
                'c = it[i].{0};',
                'if (c) {',
                   'r.push(c);',
                '}',
            '}',
            'return r;'
        ].join(''),

        /*
        如

        function(){

             var r = [],
                 i = 0,
                 it = arguments[0], // 要判断的组件列表
                 l = it.length,
                 c;
             for (; i < l; i++) {
                 c = it[i].isDisabled(); // 每个组件如果运行的方法返回真
                 if (c) {
                    r.push(c);
                 }
             }
             return r;
        }
        * */

        // 运行operation封装的方法
        filterItems = function(items, operation) {
            return operation.method.apply(this, [ items ].concat(operation.args));
        },

        // 获取items的下级容器或直接子容器
        getItems = function(items, mode) {
            var result = [],
                i,
                ln = items.length,
                candidate,
                deep = mode != '>';
            for (i = 0; i < ln; i++) {
                candidate = items[i];
                if (candidate.getRefItems) {
                    result = result.concat(candidate.getRefItems(deep));
                }
            }
            return result;
        },

        // 获取items的上级容器
        getAncestors = function(items) {
            var result = [],
                i,
                ln = items.length,
                candidate;
            for (i = 0; i < ln; i++) {
                candidate = items[i];
                while (!!(candidate = candidate.ownerCt)) {
                    result.push(candidate);
                }
            }
            return result;
        },

        
        filterByXType = function(items, xtype, shallow) {
            if (xtype == '*') {
                return items.slice();
            }
            else {
                var result = [],
                    i,
                    ln = items.length,
                    candidate;
                for (i = 0; i < ln; i++) {
                    candidate = items[i];
                    if (candidate.isXType(xtype, shallow)) {
                        result.push(candidate);
                    }
                }
                return result;
            }
        },

        
        filterByClassName = function(items, className) {
            var result = [],
                i,
                ln = items.length,
                candidate;
            for (i = 0; i < ln; i++) {
                candidate = items[i];
                if (candidate.el ? candidate.el.hasCls(className) : candidate.initCls().contains(className)) {
                    result.push(candidate);
                }
            }
            return result;
        },

        
        filterByAttribute = function(items, property, operator, value) {
            var result = [],
                i,
                ln = items.length,
                candidate;
            for (i = 0; i < ln; i++) {
                candidate = items[i];
                if ((value === undefined) ? !!candidate[property] : (candidate[property] == value)) {
                    result.push(candidate);
                }
            }
            return result;
        },

        
        filterById = function(items, id) {
            var result = [],
                i,
                ln = items.length,
                candidate;
            for (i = 0; i < ln; i++) {
                candidate = items[i];
                if (candidate.getItemId() == id) {
                    result.push(candidate);
                }
            }
            return result;
        },

        
        filterByPseudo = function(items, name, value) {
            return cq.pseudos[name](items, value);
        },

        
        
        modeRe = /^(\s?([>\^])\s?|\s|$)/,

        
        
        tokenRe = /^(?:(#)?([\w-]+|\*)(?:\((true|false)\))?)|(?:\{([^\}]+)\})/,

        matchers = [{
            // 例.container(true)，前面表示类型，括号内表示浅度遍历（本意是可以决定是否浅度遍历，然而即使选false，捕获到的是字符串'false'，其值仍然等同于true，因此不会有深度遍历的可能）
            re: /^\.([\w-]+)(?:\((true|false)\))?/,
            method: filterByXType
        },{
            
            re: /^(?:[\[\{](?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
            method: filterByAttribute
        }, {
            // id选择器
            re: /^#([\w-]+)/,
            method: filterById
        }, {
            re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/, // 其形式为:aaa(bbb) 如:not(selector)
            method: filterByPseudo // 伪类，然而空有方法，没有对应的实现
        }];

    // 查询对象
    cq.Query = Ext.extend(Object, {
        constructor: function(cfg) {//参数：{ operations: operations }
            cfg = cfg || {};
            Ext.apply(this, cfg);
        },

        // 查询root下满足查询条件的组件
        execute : function(root) {
            var operations = this.operations,
                ln = operations.length,
                operation, i,
                workingItems;

            // 如果没有指定根组件，就默认全局搜索（相当于jquery的$(selector)）
            // 注：只有通过Ext.ComponentMgr注册的组件实例才在全局定义之内
            if (!root) {
                workingItems = Ext.ComponentMgr.all.items.slice();
            }

            // 遍历查询操作对象
            for (i = 0; i < ln; i++) {

                operation = operations[i]; // 查询操作

                // 如果是^标志符
                if (operation.mode == '^') {
                    workingItems = getAncestors(workingItems || [root]); // 获取上级容器
                }
                else if (operation.mode) { // mode值为 ' '、 '<' 的情况
                    workingItems = getItems(workingItems || [root], operation.mode);// 获取下级组件
                }
                else {
                    // 筛选满足条件的组件
                    workingItems = filterItems(workingItems || getItems([root]), operation);
                }

                if (i == ln -1) { return workingItems; } // 遍历结束
            }
            return [];
        },

        is: function(component) {
            var operations = this.operations,
                ln = operations.length,
                i,
                workingItems = Ext.isArray(component) ? component : [ component ];

            
            
            for (i = 0; i < ln && workingItems.length; i++) {
                workingItems = filterItems(workingItems, operations[i]);
            }
            return workingItems.length != 0;
        }
    });


    // 对外提供的方法
    Ext.apply(this, {

        
        cache: {},

        
        pseudos: {},

        // 查询 root 下的子组件，selector 为查询字符串，如 .component、#myContainer、component[autoScroll]、panel[title="Test"]
        query: function(selector, root) {

            var selectors = selector.split(','), // 将逗号隔开的选择器转换成数组
                ln = selectors.length,
                i, 
                query, 
                results = [],
                noDupResults = [], 
                dupMatcher = {}, 
                resultsLn, 
                cmp;

            // 遍历每个独立的选择器
            for (i = 0; i < ln; i++) {
                selector = Ext.util.Format.trim(selectors[i]); // 去掉首尾空白字符
                query = this.cache[selector]; // 从缓存中拿到查询结果

                // 如果缓存中无结果
                if (!query) {

                    // 查询出结果后放入缓存中（带查询信息的cq.Query对象）
                    this.cache[selector] = query = this.parse(selector);
                }

                // 查询root下满足查询条件的组件
                results = results.concat(query.execute(root));
            }

            
            
            if (ln > 1) {
                resultsLn = results.length;

                // 遍历查询出来的组件
                for (i = 0; i < resultsLn; i++) {
                    cmp = results[i];

                    // 保证每个组件不重复
                    if (!dupMatcher[cmp.id]) {
                        noDupResults.push(cmp);
                        dupMatcher[cmp.id] = true;
                    }
                }
                results = noDupResults;
            }
            return results;
        },

        
        is: function(component, selector) {
            if (!selector) {
                return true;
            }
            var query = this.cache[selector];
            if (!query) {
                this.cache[selector] = query = this.parse(selector);
            }
            return query.is(component);
        },

        // 根据选择器查询出中间结果
        parse: function(selector) {

            /*

                matchers = [{
                    
                    re: /^\.([\w-]+)(?:\((true|false)\))?/,
                    method: filterByXType
                },{
                    
                    re: /^(?:[\[\{](?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
                    method: filterByAttribute
                }, {
                    
                    re: /^#([\w-]+)/,
                    method: filterById
                }, {
                    re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
                    method: filterByPseudo
                }];

            */

            var operations = [],
                ln = matchers.length,
                lastSelector,
                tokenMatch,
                matchedChar,
                modeMatch,
                selectorMatch,
                args,
                i, matcher;

            
            
            // 选择器还没遍历完
            while (selector && lastSelector != selector) {
                lastSelector = selector;

                //tokenRe = /^(?:(#)?([\w-]+|\*)(?:\((true|false)\))?)|(?:\{([^\}]+)\})/,
                // 选择器是否满足查询模式（包括表达式）
                tokenMatch = selector.match(tokenRe);

                // 如果满足
                if (tokenMatch) {
                    matchedChar = tokenMatch[1];

                    // 如果满足 #aaa的形式
                    if (matchedChar == '#') {
                        operations.push({
                            method: filterById, // 查询方法用filterById
                            args: [Ext.util.Format.trim(tokenMatch[2])] // 参数为aaa
                        });
                    }
                    
                    // 如果满足 .aaa的形式
                    else if (matchedChar == '.') {
                        operations.push({
                            method: filterByClassName,// 查询方法用filterByClassName
                            args: [Ext.util.Format.trim(tokenMatch[2])]
                        });
                    }
                    // 如果满足{isDisabled()}的形式
                    else if (tokenMatch[4]) {
                        operations.push({

                            // 查询方法用 比如isDisabled() 套入方法模版后的新方法
                            method: new Function(Ext.util.Format.format(filterFnPattern, tokenMatch[4])),
                            args: []
                        });
                    }
                    //比如aaa或aaa(true)这样的字符串，aaa表示标签，对应xtype，true作为参数
                    else {
                        operations.push({
                            method: filterByXType,// 查询方法用filterByXType
                            args: [Ext.util.Format.trim(tokenMatch[2]), Boolean(tokenMatch[3])]
                        });
                    }

                    // 将第一个匹配去掉
                    selector = selector.replace(tokenMatch[0], '');
                }

                
                
                // modeRe = /^(\s?([>\^])\s?|\s|$)/,
                // 如果selector没有匹配 < 或 空白字符
                while (!(modeMatch = selector.match(modeRe))) {
                    
                    // 遍历每个matchers元素
                    for (i = 0; selector && i < ln; i++) {
                        matcher = matchers[i];
                        selectorMatch = selector.match(matcher.re); // 与matcher的表达式匹配

                        
                        
                        // 如果与模式匹配，则使用对应的method和参数
                        if (selectorMatch) {
                            operations.push({
                                method: matcher.method,
                                args: selectorMatch.splice(1) // 去掉第一个元素后的数组
                            });
                            selector = selector.replace(selectorMatch[0], '');
                            break; 
                        }
                        
                        
                        if (i == (ln - 1)) {
                            throw "Invalid ComponentQuery selector: \"" + arguments[0] + "\"";
                        }
                    }
                }

                
                
                
                // 如果有比如>这样的字符
                if (modeMatch[1]) { 
                    operations.push({
                        mode: modeMatch[2]||modeMatch[1] // 将字符放入operations操作数组元素中
                    });
                    selector = selector.replace(modeMatch[0], ''); // 移掉匹配的字符串
                }
            }

            
            // 返回查询对象
            return new cq.Query({
                operations: operations
            });
        }
    });
};